package com.wfy.asyncloader

import androidx.lifecycle.Lifecycle
import com.wfy.orchestra.dispatch.ITask
import com.wfy.orchestra.dispatch.OnErrorListener
import com.wfy.orchestra.dispatch.lifecycle.LifecycleTaskGraph
import com.wfy.orchestra.thread.PoolTaskExecutor
import com.wfy.orchestra.thread.SingleExecutor
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger

/**
 * @author : wangfengyuan
 * e-mail  : 446950883@qq.com
 * time    : 2025/3/20
 * desc    :
 * version : 1.0
 */

class DefaultTaskGraphTest {
    private lateinit var defaultExecutor: PoolTaskExecutor
    private lateinit var mainExecutor: SingleExecutor
    private lateinit var executedTasks: MutableList<String>
    private lateinit var lifecycleOwner: TestLifecycleOwner
    private lateinit var graph: LifecycleTaskGraph
    private lateinit var latch: CountDownLatch

    // 自定义测试任务，记录执行顺序
    private inner class TestTask(
        override val id: String,
        override var priority: Int = 1,
        private val onExecute: () -> Unit = {}
    ) : ITask {
        override fun execute() {
            executedTasks.add(id)
            println("TestTask $id execute")
            onExecute.invoke()
        }

        override fun onCancelled() {
            executedTasks.add("$id-Cancelled")
        }
    }

    @Before
    fun setUp() {
        println("setUp exe")
        //mock出来的PoolTaskExecutor这些用不了
        defaultExecutor = PoolTaskExecutor(8)
        mainExecutor = SingleExecutor()
        graph = LifecycleTaskGraph(defaultExecutor, mainExecutor)
        executedTasks = mutableListOf()
        lifecycleOwner = TestLifecycleOwner()
    }

    //二、DAG 结构测试用例
    /**
     * 单一任务无依赖
     */
    @Test
    fun testSingleTask() {
        latch = CountDownLatch(1)
        val task = TestTask("T1") {
            latch.countDown()
        }
        graph.addTask(task)
        graph.start()
        latch.await(2, TimeUnit.SECONDS)
        assertEquals(listOf("T1"), executedTasks)
    }

    /**
     * 线性依赖链（A → B → C）
     */
    @Test
    fun testLinearDependency() {
        val taskA = TestTask("A") {
            latch.countDown()
        }
        val taskB = TestTask("B") {
            latch.countDown()
        }
        val taskC = TestTask("C") {
            latch.countDown()
        }
        val args = listOf(taskA, taskB, taskC)
        latch = CountDownLatch(args.size)
        graph.addTask(*args.toTypedArray())
        graph.addDependency("B", "A")
        graph.addDependency("C", "B")
        graph.start()
        latch.await(2, TimeUnit.SECONDS)
        assertEquals(listOf("A", "B", "C"), executedTasks)
    }


    /**
     * 并行分支（A → B, A → C）
     */
    @Test
    fun testParallelBranches() {
        val taskA = TestTask("A") {
            latch.countDown()
        }
        val taskB = TestTask("B") {
            latch.countDown()
        }
        val taskC = TestTask("C") {
            latch.countDown()
        }
        val args = listOf(taskA, taskB, taskC)
        latch = CountDownLatch(args.size)
        graph.addTask(*args.toTypedArray())
        graph.addDependency("B", "A")
        graph.addDependency("C", "A")
        graph.start()
        latch.await(2, TimeUnit.SECONDS)
        assertTrue(executedTasks.containsAll(listOf("A", "B", "C")))
        assertEquals("A", executedTasks[0]) // A必须首先执行
    }

    /**
     * 多依赖任务（A → C, B → C）
     */
    @Test
    fun testMultiDependencies() {
        val taskA = TestTask("A") {
            latch.countDown()
        }
        val taskB = TestTask("B") {
            latch.countDown()
        }
        val taskC = TestTask("C") {
            latch.countDown()
        }
        val args = listOf(taskA, taskB, taskC)
        latch = CountDownLatch(args.size)
        graph.addTask(*args.toTypedArray())
        graph.addDependency("C", listOf("A", "B"))
        graph.start()

        latch.await(2, TimeUnit.SECONDS)
        assertTrue(executedTasks.containsAll(listOf("A", "B")))
        assertEquals("C", executedTasks.last()) // C必须最后执行
    }

    //三、优先级与动态调整测试
    /**
     * 优先级覆盖依赖（高优先级优先）
     */
    @Test
    fun testPriorityOverDependency() {
        val taskLow = TestTask("Low", priority = 1) {
            latch.countDown()
        }
        val taskHigh = TestTask("High", priority = 10) {
            latch.countDown()
        }
        val args = listOf(taskLow, taskHigh)
        latch = CountDownLatch(args.size)
        graph.addTask(*args.toTypedArray())
        graph.addDependency("High", "Low")
        graph.start()
        latch.await(2, TimeUnit.SECONDS)
        assertEquals("Low", executedTasks[0]) // 高优先级任务因依赖等待
        assertEquals("High", executedTasks[1])
    }

    /**
     * 动态更新优先级
     */
    @Test
    fun testDynamicPriorityUpdate() {
        val task1 = TestTask("T1", priority = 1) {
            latch.countDown()
        }
        val task2 = TestTask("T2", priority = 1) {
            latch.countDown()
        }
        val args = listOf(task1, task2)
        latch = CountDownLatch(args.size)
        graph.addTask(*args.toTypedArray())
        graph.start()
        graph.updatePriority("T2", 10) // 提升优先级
        latch.await(2, TimeUnit.SECONDS)
        assertEquals("T2", executedTasks[0]) // 优先级调整后优先执行
    }

    //四、错误处理与生命周期测试
    /**
     * 错误传播与任务取消
     */
    @Test
    fun testErrorPropagation() {
        var errorTriggered = false
        val errorTask = TestTask("Error", onExecute = {
            latch.countDown()
            throw RuntimeException()
        })
        val dependentTask = TestTask("Dependent") {
            latch.countDown()
        }
        val args = listOf(errorTask, dependentTask)
        latch = CountDownLatch(args.size)
        graph.addTask(*args.toTypedArray())
        graph.addDependency("Dependent", "Error")
        graph.setOnErrorListener(object : OnErrorListener {
            override fun onError(task: ITask, cause: Throwable) {
                errorTriggered = true
            }
        })
        graph.start()
        latch.await(2, TimeUnit.SECONDS)
        assertTrue(errorTriggered)
        assertFalse(executedTasks.contains("Dependent")) // 依赖任务未执行
    }

    /**
     * 生命周期绑定自动取消
     */
    @Test
    fun testLifecycleAutoCancel() {
        val latch = CountDownLatch(1)
        val task = TestTask("T1") {
            latch.countDown()
        }
        graph.addTask(task)
        graph.bindToLifecycle(lifecycleOwner.lifecycle)
        //no event down from INITIALIZED
        lifecycleOwner.simulateEvent(Lifecycle.Event.ON_CREATE)
        lifecycleOwner.simulateEvent(Lifecycle.Event.ON_DESTROY)
        latch.await(2, TimeUnit.SECONDS)
        assertTrue(executedTasks.contains("T1-Cancelled")) // 生命周期销毁触发取消
    }

    //五、复杂场景与可视化验证
    /**
     * 循环依赖检测
     */
    @Test(expected = IllegalStateException::class)
    fun testCycleDetection() {
        val taskA = TestTask("A")
        val taskB = TestTask("B")

        val args = listOf(taskA, taskB)
        latch = CountDownLatch(args.size)
        graph.addTask(*args.toTypedArray())
        graph.addDependency("A", "B")
        graph.addDependency("B", "A") // 创建循环依赖
        graph.start()
    }

    /**
     * 依赖可视化验证
     */
    @Test
    fun testGenerateDotGraph() {
        val taskA = TestTask("A")
        val taskB = TestTask("B")

        val args = listOf(taskA, taskB)
        graph.addTask(*args.toTypedArray())
        graph.addDependency("B", "A")

        val expected = """
        digraph G {
          "A" -> "B";
        }
    """.trimIndent()
        assertEquals(expected, graph.generateDotGraph())
    }

    /**
     * 并发性能测试
     */
    @Test
    fun `stress test with independent tasks`() {
        // 创建无依赖任务
        val completionCounter = AtomicInteger(0)
        val taskCount = 1000
        latch = CountDownLatch(taskCount)
        repeat(taskCount) { i ->
            graph.addTask(object : ITask {
                override val id = "task$i"
                override var priority = i % 5
                override fun execute() {
                    Thread.sleep(100) // 模拟耗时操作
                    completionCounter.incrementAndGet()
                    latch.countDown()
                }
            })
        }

        graph.start()

        // 等待所有任务完成 并发任务请延长合理的等待时间，2s的话可能任务并没有跑完，await就因为超时提前结束了
        latch.await(100, TimeUnit.SECONDS)
        assertEquals(taskCount, completionCounter.get())
    }

    /**
     * 复杂依赖验证
     */
    @Test
    fun `stress test with deep dependencies`() {
        val completedTasks = ConcurrentHashMap<String, Boolean>()
        val taskCount = 1000
        latch = CountDownLatch(taskCount)
        // 创建链式依赖任务：task0 → task1 → ... → taskN
        (0 until taskCount).forEach { i ->
            graph.addTask(object : ITask {
                override val id = "task$i"
                override var priority = 1
                override fun execute() {
                    completedTasks[id] = true
                    latch.countDown()
                }
            })
            if (i > 0) {
                graph.addDependency("task$i", "task${i-1}")
            }
        }

        graph.start()

        latch.await(100, TimeUnit.SECONDS)
        // 验证最终任务是否最后执行
        assertTrue(completedTasks.containsKey("task${taskCount-1}"))
    }

    /**
     * 错误处理压测
     */
    @Test
    fun `stress test error propagation`() {
        val errorCounter = AtomicInteger(0)
        graph.setOnErrorListener(object :OnErrorListener{
            override fun onError(task: ITask, cause: Throwable) {
                errorCounter.incrementAndGet()
            }
        })
        val taskCount = 1001
        latch = CountDownLatch(taskCount)
        // 创建会失败的任务及其依赖链
        val ERROR_TASK_ID = "errorTask"
        graph.addTask(object : ITask {
            override val id = ERROR_TASK_ID
            override var priority = 1
            override fun execute() {
                latch.countDown()
                throw RuntimeException("Simulated failure")
            }
        })

        (1..taskCount).forEach { i ->
            graph.addTask(object : ITask {
                override val id = "dependent$i"
                override var priority = 1
                override fun execute() {
                    latch.countDown()
                }
            })
            graph.addDependency("dependent$i", ERROR_TASK_ID)
        }

        graph.start()

        latch.await(100, TimeUnit.SECONDS)
        // 验证错误回调触发且依赖任务被取消
        assertTrue(errorCounter.get() >= 1)
//        assertTrue(graph.runningTasks.isEmpty())
    }
}